import java.util.Arrays;
import java.util.Scanner;

/**
 * @author yexy
 * @date 2020/6/2 11:13 上午
 * @description
 * 编程实现控制台版并支持两人对战的五子棋游戏。
 * （1）绘制棋盘 - 写一个成员方法实现
 * （2）提示黑方和白方分别下棋并重新绘制棋盘 - 写一个成员方法实现。
 * （3）每当一方下棋后判断是否获胜 - 写一个成员方法实现。
 * （4）提示： 采用二维数组来模拟并描述棋盘，棋盘如下：
 */
public class Test2 {

    private char[][] gomoku;
    private char[][] board;

    public char[][] getGomoku() {
        if (this.gomoku != null) return this.gomoku;
        drawGomoku();
        return gomoku;
    }

    //绘制棋盘
    private void drawGomoku(){
        char[][] gomoku = new char[17][17];
        board = new char[16][16];
        for (int i = 0; i < gomoku.length; i++) {
           if(i == 0){
               char[] firstRow = {' ','0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
               gomoku[0] = firstRow;
           }else{
               gomoku[i][0] = gomoku[0][i];
               Arrays.fill(gomoku[i], 1, gomoku[i].length, '+');
           }
        }
        this.gomoku = gomoku;
       showGomoku();
    }

    private void showGomoku(){
        for (int i = 0; i < this.gomoku.length; i++) {
            for (int j = 0; j < this.gomoku[i].length; j++) {
                System.out.print(this.gomoku[i][j] + "\t");
            }
            System.out.println("\n");
        }
    }

    private char[][] play(char chessman,int x,int y){
        this.gomoku[y+1][x+1] = chessman;
        this.board[y][x] = chessman;
        showGomoku();
        return this.gomoku;
    }

    //每当一方下棋后判断是否获胜
    private boolean isWin(char chessman,int x,int y){

        //判断水平方向上的胜负
        if (isWinInHorizontal(chessman,x,y)) return true;

        //垂直方向上的胜负
        if (isWinInVertical(chessman,x,y)) return true;

        //判断对角线胜负
        if (isWinInDiagonal(chessman,x,y)) return true;

        return false;
    }
    //判断水平方向上的胜负
    private boolean isWinInHorizontal(char chessman,int x,int y){
        int count = 1;      //本身一点为 1
        int posX=0,posY=0;
        /**判断水平方向上的胜负
         *将水平方向以传入的点x上的y轴作为分隔线分为两部分
         *先向左边遍历，判断到的相同的连续的点  count++
         */
        for(posX = x - 1; posX >= 0 ; posX--) {
            if (this.board[posY][posX] == chessman) {
                count++;
                if (count >= 5) {
                    return true;
                }
            }else {
                break;
            }
        }    //向右边遍历
        for(posX = x + 1; posX <= 15; posX++) {
            if (this.board[posY][posX] == chessman) {
                count++;
                if (count >= 5) {
                    return true;
                }
            }else {
                break;
            }
        }
        return false;
    }

    //垂直方向上的胜负
    private boolean isWinInVertical(char chessman,int x,int y){
        int count = 1;      //本身一点为 1
        int posX=0,posY=0;
        /**判断垂直方向上的胜负
         /* 将垂直方向以传入的点y上的x轴作为分隔线分为两部分
         * 先向上遍历，判断到的相同的连续的点  count++
         */
        for(posY = y - 1; posY >= 0; posY--) {
            if (this.board[posY][posX] == chessman) {
                count++;
                if (count >= 5) {
                    return true;
                }
            }else {
                break;
            }
        }//向下遍历
        for(posY = y + 1; posY <= 15; posY++) {
            if (this.board[posY][posX] == chessman) {
                count++;
                if (count >= 5) {
                    return true;
                }
            }else {
                break;
            }
        }
        return false;
    }

    //判断对角线胜负
    private boolean isWinInDiagonal(char chessman,int x,int y){
        int count = 1;      //本身一点为 1
        int posX=0,posY=0;
        /**判断左上右下方向上的胜负
         * 以坐标点为分割线，将棋盘分为左右两个等腰三角形
         * 先判断左边的
         */
        for(posX = x - 1, posY = y - 1; posX >= 0 && posY >= 0; posX--, posY--) {
            if (this.board[posY][posX] == chessman) {
                count++;
                if (count >= 5) {
                    count = 1;
                    return true;
                }
            }else {
                break;
            }
        }//判断右边的
        for(posX = x + 1, posY = y + 1; posX <= 15 && posY <= 15; posX++, posY++) {
            if (this.board[posY][posX] == chessman) {
                count++;
                if (count >= 5) {
                    count = 1;
                    return true;
                }
            }else {
                break;
            }
        }
        /**判断右下左下方向上的胜负
         * 以坐标点为分割线，将棋盘分为左右两个等腰三角形
         * 先判断左边的
         */
        for(posX = x + 1, posY = y - 1; posX <= 15 && posY >= 0; posX++, posY--) {
            if (this.board[posY][posX] == chessman) {
                count++;
                if (count >= 5) {
                    return true;
                }
            }else {
                break;
            }
        }//判断右边的
        for(posX = x - 1, posY = y + 1; posX >= 0 && posY <= 15; posX--, posY++) {
            if (this.board[posY][posX] == chessman) {
                count++;
                if (count >= 5) {
                    return true;
                }
            }else {
                break;
            }
        }
        return false;
    }

    //提示黑方和白方分别下棋并重新绘制棋盘 - 写一个成员方法实现。
    public void beginGame(){
        this.getGomoku();
        boolean flag = true, isWin =false;
        int x=0,y=0;
        char chessman = flag ? 'B' : 'W';//false w 白棋 ： true b 黑棋
        Scanner scanner = new Scanner(System.in);

        do{
            if (flag){
                System.out.println("请黑棋下(输入坐标0=<(x y)<=16)：");
            }else {
                System.out.println("请白棋下(输入坐标0=<(x y)<=16)：");
            }
            x=scanner.nextInt();
            y=scanner.nextInt();
            chessman = flag ? 'B' : 'W';
            play(chessman,x,y);

            isWin = isWin(chessman,x,y);
            if (isWin) {
                if(flag){
                    System.out.println("黑棋赢了");
                }else {
                    System.out.println("白棋赢了");
                }
            }
            flag = !flag;

        }while (!isWin);
    }
}
